/*
 * main.cpp
 *
 *  Created on: 2010/07/18
 *      Author: terry
 */

#include <iostream>
#include <sys/inotify.h>
#include <signal.h>
#include <boost/smart_ptr.hpp>
#include <boost/bind.hpp>
#include "dir_watcher.h"
#include "dir_event.h"
#include "common.h"
#include "block_queue.h"

using namespace std;
using namespace boost;

// global dir watch pointer
dir_watcher *global_dw;

/* Signal handler that simply resets a flag to cause termination */
void signal_handler (int signum)
{
    cout << "signal_handler(" << signum << ")" << endl;
    if(global_dw != NULL){
        cout << "stop_watch()" << endl;
        global_dw->stop_watch();
    }
}

/* ディレクトリ監視イベントハンドラ */
struct event_hanlder
{
    block_queue<dir_event> *event_queue;

    void operator()(const shared_ptr<dir_event> evt)
    {
        cout << "filename=" << evt->file_name << ", event=" << evt->mask << ",";
        switch(evt->mask & (IN_ALL_EVENTS | IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED)){
        case IN_ACCESS:
            cout << "ファイルがアクセス (read) された。";
            break;
        case IN_ATTRIB:
            cout << "メタデータが変更された。";
            break;
        case IN_CLOSE_WRITE:
            cout << "書き込みのためにオープンされたファイルがクローズされた。";
            break;
        case IN_CLOSE_NOWRITE:
            cout << "書き込み以外のためにオープンされたファイルがクローズされた。";
            break;
        case IN_CREATE:
            cout << "監視対象ディレクトリ内でファイルやディレクトリが作成された。";
            break;
        case IN_DELETE:
            cout << "監視対象ディレクトリ内でファイルやディレクトリが削除された。";
            break;
        case IN_DELETE_SELF:
            cout << "監視対象のディレクトリまたはファイル自身が削除された。";
            break;
        case IN_MODIFY:
            cout << "ファイルが修正された。";
            break;
        case IN_MOVE_SELF:
            cout << "監視対象のディレクトリまたはファイル自身が移動された。";
            break;
        case IN_MOVED_FROM:
            cout << "ファイルが監視対象ディレクトリ外へ移動された。";
            break;
        case IN_MOVED_TO:
            cout << "ファイルが監視対象ディレクトリ内へ移動された。";
            break;
        case IN_OPEN:
            cout << "ファイルがオープンされた。 ";
            break;
        default:
            cout << "イベント未定義。";
        }
        cout << endl;

        event_queue->put(evt);
    }
};

/* イベントキューの消費者 */
struct event_consumer
{
    block_queue<dir_event> *event_queue;

    void operator()()
    {
        while(true)
        {
            shared_ptr<dir_event> el = event_queue->get();
            if(el.get() != NULL){
                cout << "get=" << el->file_name << endl;
            } else {
                break;
            }
        }
    }
};

/* メイン関数、入り口 */
int main()
{
    cout << "テストスタート！" << endl;

    dir_watcher dw;
    try {
        dw.open();
        global_dw = &dw;
        cout << "dir_watcher open." << endl;
    } catch (op_error& e) {
        cout << "error: " << e.what() << " errno:" << e.get_errno() << endl;
    }
    dw.add_directory("/root/download", IN_ALL_EVENTS);

    if (signal(SIGINT, signal_handler) == SIG_IGN) {
        /* Reset to SIG_IGN (ignore) if that was the prior state */
        signal(SIGINT, SIG_IGN);
    }

    block_queue<dir_event> event_queue(10000);
    event_hanlder eh;
    eh.event_queue = &event_queue;

    dw.connect(eh);

    event_consumer ec;
    ec.event_queue = &event_queue;
    thread ec_thread(ec);

    dw.start_watch();
    cout << "dir_watcher stoped." << endl;
    dw.destroy();
    cout << "dir_watcher destroy." << endl;

    event_queue.dispose();

    ec_thread.join();

    cout << "dir_watcher close." << endl;
    return 0;
}
